from django.shortcuts import render

# Create your views here.

from django.views import View
from apps.users.models import User
from django.http.response import JsonResponse

class UsernameCountView(View):


    # username/<username>/count/
    def get(self,request,username):

        # 1.根据username进行数量的查询
        count=User.objects.filter(username=username).count()
        # 2.将查询结果返回
        # code=0  表示成功
        return JsonResponse({'code':0,'errmsg':'ok','count':count})


# 注册功能类视图###############################
import json
import re
class RegisterView(View):


    def post(self,request):

        '''
        1.接受参数
        2.获取参数
        3.验证参数
        4.保存数据到MySQL
        5.状态保持(session  redis)
        6.返回响应
        :param request:
        :return:
        '''
        # 1.接受参数
        # 前端是将JSON数据以post方式传递过来的
        # 用request.body
        body=request.body             # request.body 是bytes类型数据
        body_str=body.decode()        # bytes 转 str
        data=json.loads(body_str)     # str 转 dict

        # 2.获取参数
        username=data.get('username')
        password=data.get('password')
        password2=data.get('password2')
        mobile=data.get('mobile')
        allow=data.get('allow')

        # 3.验证参数
        # 3.1 获取的我哥参数都必须有值
        # all([xxx,xxx,xxx)
        # all([])  列表中的变量，只要有一个数据为None，表达式的值就是False

        if not all([username,password,password2,mobile,allow]):
            return JsonResponse({'code':400,'errmsg':'补全参数'})

        # 3.2验证用户名是否符合规则
        if not re.match('[a-zA-Z0-9_-]{5,20}',username):
            return JsonResponse({'code':400,'errmsg':'用户名不符合规则'})
        # 3.3验证密码是否符合规则
        # 3.4确认密码 同 验证密码
        # 3.5验证手机号是否符合规则

        # 4.保存数据到MySQL
        '''
        >>> book = BookInfo(
        ...         name='python入门'
        ...         pub_date='2020-1-1'
        ...     )
        >>> book.save()
        
        >>> PeopleInfo.object.create(
        ...         name=''itheima,
        ...         book=book
        ...         )
        '''
        # user=User(username=username,password=password,mobile=mobile)
        # user.save()

        # user=User.object.create(username=username,password=password,mobile=mobile)

        # 以上两种方式都可以，但是以上两种方式都没有 加密

        # create_user 是django 认证系统提供的方法
        # 这个方法 可以对 用户的密码进行加密操作
        user=User.objects.create_user(username=username,
                                      password=password,
                                      mobile=mobile)

        # 5.状态保持(session   redis)
        # 设置session的基本操作
        # request.session['id']=user.id
        # request.session['username']=username
        # request.session['mobile']=user.mobile

        # django 自带后台--后台也是采用的session技术
        # django 实现了 session状态保持
        from django.contrib.auth import login

        # 参数1： request    # 请求对象
        # 参数2： user       # 用户信息
        login(request,user)

        # 6.返回响应
        return JsonResponse({'code':0,'errmsg':'ok'})

# ####################################
# 登录
class LoginView(View):

    def post(self,request):

        '''
        1.接收请求数据
        2.提取数据
        3.验证数据
        4.认证登录
        5.状态保持
        6.是否记住登录(类似163邮箱的10天免登陆) 设置session过期时间
        7.返回响应
        :param request:
        :return:
        '''
        # 1.接收请求数据
        data = json.loads(request.body.decode())
        # 2.提取数据
        username=data.get('username')
        password=data.get('password')
        remembered=data.get('remembered')

        # 改多账号登录###########################
        # 可以根据username 的值来判断
        if re.match('1[3-8]\d{9}',username):
            # 如果username的值为手机号，进行mobile的判断
            User.USERNAME_FIELD='mobile'
        else:
            # 如果username的值不为手机号，进行username的判断
            User.USERNAME_FIELD='username'


        # 3.验证数据
        # 用户名和密码是必须传递的！！！
        if not all([username,password]):
            return JsonResponse({'code':400,'errmsg':'参数不全'})
        # 3.1用户名规格
        # 3.2密码规格

        # 4.认证登录
        # django 自带admin后台，admin 可以验证用户和密码
        # django 实现了 用户名和密码的验证方法
        from django.contrib.auth import authenticate

        # authenticate 把用户名和密码传递过去之后，会帮助验证用户名和密码是否正确
        # 如果正确，则返回 username对应的模型对象
        # 如果不正确，则返回None

        # 设置关键字参数
        user=authenticate(username=username,password=password)

        if user is None:
            # user is None, 说明用户名或密码不正确
            # 这里不能告知 前段 准确的错误信息
            return JsonResponse({'code':400,'errmsg':'用户名或密码不正确'})
        # user 不为None 说明登录成功，继续执行后面代码

        # 5.状态保持
        from django.contrib.auth import login
        login(request,user)

        # 6.是否记住登录(类似163邮箱的10天免登陆) 设置session过期时间
        if remembered:
            # remembered  判断用户是否勾选  记住登录状态
            # 如果勾选，则让session 有效期为 两周14 天
            request.session.set_expiry(None)
        else:
            # 如果未勾选，则设置 session 有效期为 浏览器回话结束之后
            request.session.set_expiry(0)

        # 7.返回响应
        response = JsonResponse({'code':0,'errmsg':'ok'})

        # 设置cookie
        # 注意： key 必须是username  因为前端写死了
        response.set_cookie('username',username,max_age=14*24*3600)

        return response


# 退出登录######################
class LogoutView(View):

    def delete(self,request):

        # 1.删除状态保持信息
        #   request.session.clear()
        #   request.session.flush()


        # django -- login
        # django 实现了 状态保持的方法
        # django 也实现了状态删除的方法
        from django.contrib.auth import logout
        logout(request)

        # 2.把username 的cookie信息删除

        response = JsonResponse({'code':0,'errmsg':'ok'})

        response.delete_cookie('username')

        return response

#########################################
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth import authenticate
'''
LoginRequiredMixin : 判断用户是否登录

authenticate ： 判断用户名和密码是否正确
'''

# 用户中心 必须是用户登录的状态才可以访问

# LoginRequiredMixin
# 如果用户没有登录，则返回 没有权限访问
# 如果用户登录了，则 继续调用父类的dispatch方法

# class UserInfoView(View,LoginRequiredMixin):   # View 直接把dispatch方法走完了，不会调用LoginRequiredMixin的dispatch方法

from utils.views import LoginRequiredJSONMixin
'''
退出登录的情况下进行验证
LoginRequiredJSONMixin    判断没有登录返回 JSON

LoginRequiredMixin        判断没有登录返回重定向
'''
# class UserInfoView(LoginRequiredMixin,View):       # LoginRequiredMixin 返回重定向
class UserInfoView(LoginRequiredJSONMixin,View):     # LoginRequiredMixin 的dispatch 然后判断

    def get(self,request):

        '''
        1. 判断 必须是登录用户
        2. 获取用户信息
        3. 返回响应
        :param request:
        :return:
        '''

        # 用户的信息
        # request.user

        # request里有一个 user 属性
        # 这个 user 属性， 其实是系统根据我们的session信息自动添加的(方便我们操作)
        # 如果已经登录了 request.user 就是 数据库中的那个user实例对象
        user=request.user

        user_info = {
            'username': user.username,
            'mobile': user.mobile,
            'email': user.email,
            'email_active': user.email_active
        }

        # 注意： 用户信息的JSON数据中，用户的信息对应的key必须是info_data  因为前端写死了
        return JsonResponse({'code':0,'errmsg':'ok','info_data':user_info})


# 邮件保存###############################
from utils.views import LoginRequiredJSONMixin
class EmailView(LoginRequiredJSONMixin,View):

    def put(self,request):
        '''
        1. 判断用户是否登录
        2. 接收参数
        3. 提取参数
        4. 验证参数(作业)
        5. 更新用户信息(数据入库)
        6. 发送激活邮件
        7.返回响应
        :param request:
        :return:
        '''
        # 1. 判断用户是否登录
        # 2. 接收参数
        # put请求的数据也在body中
        data = json.loads(request.body.decode())
        # 3. 提取参数
        email = data.get('email')
        # 4. 验证参数(作业)
        # 5. 更新用户信息(数据入库)
        user = request.user
        user.email = email
        user.save()
        # 6. 发送激活邮件
        # 要实现发送邮件，需要设置 邮件服务器

        # from django.core.mail import send_mail
        # # subject, message, from_email, recipient_list,
        # # subject         主题
        # subject = '美多商城激活邮件'
        # # message         邮件内容
        # message = ''
        # # from_email      谁发的邮件
        # from_email = '美多商城<xiaomaidexiaobocai@163.com>'
        # # recipient_list  收件人列表[邮箱1,邮箱2...]
        # recipient_list = [email]
        #
        # # 支持 HTML
        # html_message = '<a href="#"></a>'
        #
        # send_mail(subject,
        #           message,
        #           from_email,
        #           recipient_list,
        #           html_message=html_message)

        # 生成一个 html_message

        # token 数据是一个加密的数据，这个数据中，包含用户信息就可以
        from apps.users.utils import generic_user_id

        token = generic_user_id(user.id)

        verify_url = 'http://www.meiduo.site:8080/success_verify_email.html?token=%s'%token

        html_message =  '<p>尊敬的用户您好！</p>' \
                        '<p>感谢您使用美多商城。</p>' \
                        '<p>您的邮箱为：%s 。请点击此链接激活您的邮箱：</p>' \
                        '<p><a href="%s">%s<a></p>' % (email, verify_url, verify_url)

        from celery_tasks.email.tasks import celery_send_email
        celery_send_email.delay(email,html_message)


        # 7.返回响应
        return JsonResponse({'code':0})


# ##########
class VerifyEmailView(View):

    def put(self,request):
        '''
        1. 接收数据
        2. 提取数据
        3. 对数据进行解密处理
        4. 判断有没有user_id
        5. 如果没有则说明 token过期了
        6. 如果有，则查询用户信息
        7. 改变用户的邮箱激活状态
        8. 返回响应
        :param request:
        :return:
        '''
        # 1.接收数据
        data=request.GET
        # 2. 提取数据
        token=data.get('token')
        # 3. 对数据进行解密处理
        from apps.users.utils import check_user_id
        user_id=check_user_id(token)
        # 4. 判断有没有user_id
        if user_id is None:
            # 5. 如果没有则说明 token过期了
            return JsonResponse({'code':400,'errmsg':'链接失效'})
        # 6. 如果有，则查询用户信息
        # 查询  是因为用户可能更换浏览器激活，此时的request.user就不是登录用户了
        try:
            user = User.objects.get(id=user_id)
        except User.DoesNotExist:
            return JsonResponse({'code':400,'errmsg':'链接失效'})
        # 7. 改变用户的邮箱激活状态
        user.email_active=True
        user.save()
        # 8. 返回响应
        return JsonResponse({'code':0,'errmsg':'ok'})



# 地址管理###############
from apps.users.models import Address
class CreateAddressView(LoginRequiredJSONMixin,View):

    def post(self,request):
        '''
        1.必须是登陆用户
        2.接收参数
        3.提取参数
        4.验证参数
        5.数据入库
        6.返回响应
        :param request:
        :return:
        '''
        # 1.必须是登陆用户可以新增地址   LoginRequiredJSONMixin
        # 2.接收参数
        data = json.loads(request.body.decode())

        # 3.提取参数
        receiver = data.get('receiver')
        province_id = data.get('province_id')
        city_id = data.get('city_id')
        district_id = data.get('district_id')
        place = data.get('place')
        mobile = data.get('mobile')
        tel = data.get('tel')
        email = data.get('email')

        # 4.验证参数

        # 5.数据入库
        address = Address.objects.create(
            user=request.user,
            title=receiver,
            receiver=receiver,
            province_id=province_id,
            city_id=city_id,
            district_id=district_id,
            place=place,
            mobile=mobile,
            tel=tel,
            email=email
        )
        # 6.返回响应
        address_dict = {
            'id': address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        return JsonResponse({'code':0,'errmsg':'ok','address':address_dict})



# 地址查询#########################
class AddressesListView(LoginRequiredJSONMixin,View):

    def get(self,request):
        '''
        1.必须是登录用户才可以查询地址
        2.根据用户信息查询地址信息
        3.需要对查询结果进行遍历，转换字典列表
        4.返回响应
        :param request:
        :return:
        '''
        # 1.必须是登录用户才可以查询地址     LoginRequiredJSONMixin
        # 2.根据用户信息查询地址信息
        addresses = Address.objects.filter(user=request.user,    # user 必须有
                                           is_deleted=False)
        # 3.需要对查询结果进行遍历，转换字典列表
        addresses_list = []
        for address in addresses:
            addresses_list.append({
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            })
        # 4.返回响应
        '''
        {
        'code': 0,
         'errmsg': 'ok',
         'addresses': [],
         'default_address_id': 1
        }
        '''
        return JsonResponse({'code':0,
                             'errmsg':'ok',
                             'addresses':addresses_list,
                             'default_address_id':request.user.default_address_id})



# ##########################
# 新增用户浏览记录
from apps.goods.models import SKU
from django_redis import get_redis_connection
class UserHistoryView(View):

    def post(self,request):
        '''
        0.必须是登录用户
        1.接受请求
        2.提取参数
        3.验证参数
        4.链接redis
        5.去重数据
        6.添加数据
        7.最多保存5条数据
        8.返回响应
        :param request:
        :return:
        '''
        # 1.接受请求   JSON  request.body
        data = json.loads(request.body.decode())
        # 2.提取参数
        sku_id = data.get('sku_id')
        # 3.验证参数
        try:
            SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({'code':400,'errmsg':'无此商品'})
        # 4.链接redis
        redis_cli = get_redis_connection('history')
        # 5.去重数据  (列表删除数据  sku_id)
        '''
        lrem key count value
        根据参数count的值,移除列表中与参数value相等的元素
        count > 0    从表头到表尾搜索，移除与value相等的元素，数量为count
        count < 0    从表尾到表头搜索，移除与value相等的元素，数量为count的绝对值
        count = 0    移除表中所有与value相等的元素
        '''
        redis_cli.lrem(request.user.id,0,sku_id)
        # 6.添加数据
        # lpush(key,value)
        redis_cli.lpush(request.user.id,sku_id)
        # 7.最多保存5条数据
        '''
        ltrim key start stop
        对一个列表进行修剪(trim),使列表只保留指定区间的元素
        '''
        redis_cli.ltrim(request.user.id,0,4)
        # 8.返回响应
        return ({'code':0,'errmsg':'ok'})


    def get(self,request):
        '''
        1.必须是登录用户
        2.获取用户信息
        3.链接redis
        4.查询浏览记录
        5.遍历列表数据
        6.将对象转换为字典数据
        7.返回响应
        :param request:
        :return:
        '''
        # 1.必须是登录用户    LoginRequiredJSONMixin
        # 2.获取用户信息
        user = request.user
        # 3.链接redis
        redis_cli = get_redis_connection('history')
        # 4.查询浏览记录  [1,2,3]
        # lrange(key,start,stop)
        sku_ids = redis_cli.lrange(user.id,0,-1)
        skus = []
        # 5.遍历列表数据
        for id in sku_ids:
            # 商品id在新增历史记录时 已验证，所以异常获取可不加
            sku = SKU.objects.get(id=id)
            # 6.将对象转换为字典数据
            skus.append({
                'id':sku.id,
                'name':sku.name,
                'price':sku.price,
                'default_image_url':sku.default_image.url
            })
        # 7.返回响应
        return JsonResponse({'code':0,'skus':skus,'errmsg':'ok'})




